package com.aries.updater;

import android.app.Dialog;
import android.app.DownloadManager;
import android.content.DialogInterface;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.RecoverySystem;
import android.os.SystemProperties;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.beiing.flikerprogressbar.FlikerProgressBar;
import com.dd.CircularProgressButton;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, Runnable {

    private TextView current_version_view;
    private TextView new_version_view;
    private TextView update_message_text;
    private CircularProgressButton button;
    private FlikerProgressBar download_progress_bar;
    private Thread downLoadThread;
    private long downloadId;
    private DownloadManager downloadManager;
    private String current_version = null;
    private String new_version = null;
    private LinearLayout no_update_view;
    private LinearLayout update_message_view;
    private String ota_url = null;
    private String full_url = null;
    private String need_version = null;
    private String ota_size = null;
    private String full_size = null;
    private String file_size = null;
    private String file_name = null;
    private String download_url = null;
    private String update_message = null;
    private String ota_md5 = null;
    private String full_md5 = null;
    private String file_md5 = null;
    private String download_file_md5 = null;
    private String json;
    private File otaZip = null;

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            download_progress_bar.setProgress(msg.arg1);
            if(msg.arg1 == 100){
                download_progress_bar.finishLoad();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
        initView();
        check();
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()) {
            case R.id.update_button:
                if (!isSameVersion()) {
                    if (!isOTADownloaded()) {
                        button.setVisibility(View.INVISIBLE);
                        download_progress_bar.setVisibility(View.VISIBLE);
                        downloadId = downloadFile(download_url, file_name, downloadManager);
                        downLoadThreadStart();
                    } else {
                        otaZip = Environment.getExternalStoragePublicDirectory("/sdcard/Download/" + file_name + ".zip");
                        File file = new File("/sdcard/Download/" + file_name + ".zip");
                        download_file_md5 = getFileMD5(file);
                        if (download_file_md5.equals(file_md5)) {
                            try {
                                RecoverySystem.installPackage(MainActivity.this, otaZip);
                            } catch (IOException e) {
                                Log.e("", e.getMessage());
                            }
                        } else {
                            if (file.exists()) {
                                file.delete();
                            }
                            Dialog alertDialog = new AlertDialog.Builder(this).
                                    setTitle(getResources().getString(R.string.md5_error_title)).
                                    setMessage(getResources().getString(R.string.md5_error_message)).
                                    setPositiveButton(getResources().getString(R.string.download_again), new DialogInterface.OnClickListener() {

                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            button.setVisibility(View.INVISIBLE);
                                            download_progress_bar.setVisibility(View.VISIBLE);
                                            downloadId = downloadFile(download_url, file_name, downloadManager);
                                            downLoadThreadStart();
                                        }
                                    }).
                                    setNegativeButton(getResources().getString(R.string.cancel_update), new DialogInterface.OnClickListener() {

                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            button.setVisibility(View.VISIBLE);
                                            download_progress_bar.setVisibility(View.INVISIBLE);
                                            button.setProgress(0);
                                            button.setCompleteText(getResources().getString(R.string.download_now));
                                            check();
                                        }
                                    }).
                                    create();
                            alertDialog.show();
                        }
                    }
                } else {
                    check();
                }
                break;
            default:
                break;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void updateUI(UpdateMessage updateMessage) {
        new_version_view.setText(getResources().getString(R.string.new_version_string) + new_version);
        if (!isSameVersion()) {
                button.setProgress(100);
                no_update_view.setVisibility(View.INVISIBLE);
                update_message_view.setVisibility(View.VISIBLE);
            if (current_version.equals(need_version)) {
                download_url = ota_url;
                file_name = "miui_aries_6.0_" + need_version + "_to_" + new_version;
                file_size = ota_size;
                file_md5 = ota_md5;
            } else {
                download_url = full_url;
                file_name = "miui_aries_6.0_" + new_version;
                file_size = full_size;
                file_md5 = full_md5;
            }
                update_message_text.setText(getResources().getString(R.string.file_size) + file_size + "\n"
                        + getResources().getString(R.string.update_message_string) + "\n"
                        + update_message);
            if (isOTADownloaded()) {
                button.setCompleteText(getResources().getString(R.string.install_package));
            } else {
                button.setCompleteText(getResources().getString(R.string.download_now));
            }
        } else {
            button.setProgress(0);
            no_update_view.setVisibility(View.VISIBLE);
            update_message_view.setVisibility(View.INVISIBLE);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void updateFinishedUI(DownloadFinish downloadFinish) {
        download_progress_bar.reset();
        button.setVisibility(View.VISIBLE);
        download_progress_bar.setVisibility(View.INVISIBLE);
        button.setIdleText("");
        button.setText("");
        button.setProgress(0);
        button.setProgress(100);
        button.setCompleteText(getResources().getString(R.string.install_package));
    }

    private boolean isOTADownloaded() {
        File file = new File("/sdcard/Download/" + file_name + ".zip");
        return file.exists();
    }

    private void initView() {
        current_version_view = (TextView)findViewById(R.id.current_version);
        new_version_view = (TextView)findViewById(R.id.new_version);
        button = (CircularProgressButton)findViewById(R.id.update_button);
        no_update_view = (LinearLayout)findViewById(R.id.no_update_view);
        update_message_view = (LinearLayout)findViewById(R.id.update_message_view);
        update_message_text = (TextView)findViewById(R.id.update_message);
        downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
        download_progress_bar = (FlikerProgressBar) findViewById(R.id.download_progress_bar);
        button.setOnClickListener(this);
        setCurrent_version();
    }

    private void downLoadThreadStart() {
        downLoadThread = new Thread(this);
        downLoadThread.start();
    }

    private long downloadFile(String ri, String file_name, DownloadManager downloadManager) {
        Uri uri = Uri.parse(ri);
        DownloadManager.Request request = new DownloadManager.Request(uri);
        request.setDestinationInExternalPublicDir("Download", file_name + ".zip");
        request.setDescription(file_name + ".zip" + getResources().getString(R.string.download_string));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setVisibleInDownloadsUi(true);
        return downloadManager.enqueue(request);
    }


    private boolean isSameVersion() {
        return current_version.equals(new_version);
    }

    private String getCurrentVersion() {
        current_version = SystemProperties.get("ro.build.version.incremental");
        return current_version;
    }

    private void setCurrent_version() {
        current_version_view.setText(getResources().getString(R.string.current_version_string) + getCurrentVersion());
    }

    private void check() {
        button.setIndeterminateProgressMode(true);
        button.setProgress(50);
        new Thread(new Runnable() {
            @Override
            public void run() {
                json = getJson();
                parseJSONWithJSONObject(json);
                EventBus.getDefault().post(new UpdateMessage());
            }
        }).start();
    }

    private static String getJson() {
        StringBuffer str = new StringBuffer();
        try {
            URL url1 = new URL("https://git.oschina.net/guaiyihu/android_packages_aries_updater/raw/master/app/site/site.json");
            HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
            InputStreamReader r = new InputStreamReader(conn.getInputStream());
            BufferedReader rd = new BufferedReader(r);
            String line;
            while ((line = rd.readLine()) != null) {
                str.append(line);
            }
            rd.close();
        } catch (Exception e) {
        }
        return str.toString();
    }

    private void parseJSONWithJSONObject(String jsonData) {
        try {
            JSONObject jsonObject = new JSONObject(jsonData);
            try {
                new_version = jsonObject.getString("version");
                need_version = jsonObject.getString("need_version");
                ota_url = jsonObject.getString("ota_url");
                full_url = jsonObject.getString("full_url");
                ota_size = jsonObject.getString("ota_size");
                full_size = jsonObject.getString("full_size");
                update_message = jsonObject.getString("message");
                ota_md5 = jsonObject.getString("ota_md5");
                full_md5 = jsonObject.getString("full_md5");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            while(!downLoadThread.isInterrupted()){
                float progress = download_progress_bar.getProgress();
                DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
                Cursor cursor = null;
                try {
                    cursor = downloadManager.query(query);
                    if (cursor != null && cursor.moveToFirst()) {
                        long downloadedBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                        long totalBytes = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                        progress = (float) downloadedBytes/totalBytes * 100;
                    }
                } finally {
                    if (cursor != null) {
                        cursor.close();
                    }
                }
                Thread.sleep(100);
                Message message = handler.obtainMessage();
                message.arg1 = (int) progress;
                handler.sendMessage(message);
                if(progress == 100){
                    EventBus.getDefault().post(new DownloadFinish());
                    break;
                }
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    public static String getFileMD5(File file) {
        if (!file.isFile()) {
            return null;
        }
        MessageDigest digest = null;
        FileInputStream in = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = MessageDigest.getInstance("MD5");
            in = new FileInputStream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BigInteger bigInt = new BigInteger(1, digest.digest());
        return bigInt.toString(16);
    }

}
